--
-- Author: shineflag
-- Date: 2017-02-15 19:14:08
--


local skynet = require "skynet"
local log = require "log"
local proto = require("json_proto")
local json = require("json")
local cluster = require("skynet.cluster")

local TAG =  "TABLEMANAGER"

local ORDER6 = {5,4,3,1,2,0}  --6人桌的配桌顺序
local ORDER9 = {1,2,3,4,8,7,6,5,0} --9人桌的配桌顺序

local lobby 

local CMD = {}
local conf         --该场次的配置信息
local gtables = {}   --所有桌子信息 tid为key
--local player_tables = {}  --以人数为key
local tcount = 0    --桌子数 
local alloc_order   --匹配序列 根据人数
local seat_num      --桌子的座位数

local game_proxy = {}   --现金桌代理
local cur_game_group    --当前的现金桌组

local meta = {}  --本服务的逻辑


--获取相应组的桌子列表
function meta.player_table_list( pnum, group)
	group = group or cur_game_group
	if not group then 
		log.e(TAG,"not start group pnum[%d]",pnum)
		return nil
	end
	local player_tables = game_proxy[group].player_tables
	return player_tables[pnum]
end

--将桌子列表插到相应的组
function meta.player_table_insert(list,pnum,group)
	log.d(TAG,"insert list group[%s] pnum[%d]",group, pnum)
	local player_tables = game_proxy[group].player_tables
	player_tables[pnum] = list
end


--将一个桌子从人数列表中移除
function meta.remove_player_list(gtable)
	local list = meta.player_table_list(gtable.player,gtable.group)
	if list and #list > 0 then 
		for id, v in ipairs(list) do 
			if v.tid == gtable.tid then 
				table.remove(list,id)
				log.d(TAG,"found player[%d] list gtable[%d]",gtable.player,gtable.tid)
				return
			end
		end
	end

	log.e(TAG,"not found player[%d] list gtable[%d]",gtable.player,gtable.tid)
end

--更新一个桌子的人数及人数桌子列表 
function meta.update_table_player(gtable)
	local list = meta.player_table_list(gtable.player,gtable.group)
	if not list then 
		list = {}
		meta.player_table_insert(list, gtable.player, gtable.group)
	end
	table.insert(list, gtable)
end

--创建一个桌子
function meta.create_gtable()

	local tid = skynet.call(game_proxy[cur_game_group].handler,"lua","create_table",seat_num,conf.lv)

	if tid then
		skynet.call(game_proxy[cur_game_group].handler,"lua","texas_conf",tid, conf)
		local gtable = {
			tid = tid,
			player = 0,   --玩家数量
			watcher = 0,  --观战者数量
			status = 0,   --游戏桌子的状态
			group = cur_game_group,
		}
		log.d(TAG,"group[%s] create table[%d] thandler[%x] ",cur_game_group,tid,gtable.handler)

		gtables[tid] = gtable

		meta.update_table_player(gtable)

		return gtable 
	else
		log.e(TAG,"create ctable failed")
	end

end

--在同步信息前清掉 当前组的桌子信息
function meta.clear_group_gtables(group)
	log.d(TAG, "clear_group_gtables group[%s]",group)
	for tid, gtable in pairs(gtables) do 
		if gtable.group == group then 
			log.e(TAG, "clear_group_gtables gtable[%s]",json.encode(gtable))
			gtables[tid] = nil
		end
	end
end

--同步在玩信息方便 重连
function meta.syn_game_play_info(group, proxy)
	local ok, rstatus,info = pcall(skynet.call, proxy, "lua", "syn_play_info", conf.lv)
	if ok then 
		meta.clear_group_gtables(group)
		game_proxy[group] = {handler = proxy,player_tables={} }
		if not rstatus then 
			log.e(TAG,"game group[%s] is active",group)
			cur_game_group = group
		end
		for tid, mids in pairs(info) do 

			local gtable = {
				tid = tid,
				player = #mids,   --玩家数量
				watcher = 0,      --观战者数量
				status = 0,       --游戏桌子的状态
				group = group,
			}
			log.d(TAG,"syn game lv[%d] table[%d] has mids[%s] thandler[%x]",conf.lv, tid, json.encode(mids), gtable.handler )
			gtables[tid] = gtable
			meta.update_table_player(gtable)
		end
	end
end

--同步现金场的在玩信息
function meta.syn_game_info()
	local groups = {"cluster_game_1","cluster_game_2"}
	for _, group in ipairs(groups) do
		local proxy = meta.get_game_proxy(group,sname)
		if proxy then 
			meta.syn_game_play_info(group, proxy)
		end
	end
end

--当一个现金场启动时上报 
--同步该现金场的在玩信息
function meta.connect_game_group(group,sname)
	log.d(TAG,"report_game_group group[%s] sname[%s]",group, sname)
	local proxy = meta.get_game_proxy(group,sname)
	if proxy then 
		
	end
end

--当玩家只配置桌不入桌时，可能会导致在玩人数不正确
function meta.syn_active_game_players()

	if not cur_game_group or not game_proxy[cur_game_group] or not game_proxy[cur_game_group].handler then 
		log.e(TAG,"not active game")
		return 
	end

	local ok, rstatus,info = pcall(skynet.call, game_proxy[cur_game_group].handler, "lua", "syn_play_info", conf.lv)
	if ok then 
		for tid, mids in pairs(info) do 
			local gtable = gtables[tid]
			if not gtable then 
				gtable = {
					tid = tid,
					player = #mids,   --玩家数量
					watcher = 0,      --观战者数量
					status = 0,       --游戏桌子的状态
					group = group,
				}
				gtables[tid] = gtable
				meta.update_table_player(gtable)
				log.e(TAG,"syn_active_game_players not found table[%s]",tid)
			end
			log.d(TAG,"syn_active_game_players lv[%d] table[%d] has mids[%s] ",conf.lv, tid, json.encode(mids))

			if gtable.player ~= #mids then 
				log.e(TAG,"syn_active_game_players gtable[%d] pnum[%d] != #mids[%d]",tid,gtable.player, #mids )
				gtable.player = #mids 
				meta.update_table_player(gtable)
			end
		end
	end
end

function CMD.init(src,c)
	TAG = TAG .. c.lv
	lobby = src
	conf = c

	alloc_order = {}
	seat_num = c.seatnum 
	if c.seatnum == 9 then
		alloc_order = ORDER9 
	elseif c.seatnum == 6 then
		alloc_order = ORDER6 
	else
		for i = 1, c.seatnum-1 do
			table.insert(alloc_order,i)
		end
		table.insert(alloc_order,0)
	end
	log.d(TAG,"start tablemanger[%s]",c.name)
	log.d(TAG,"seatnum[%d] lobby order: [%s]",seat_num,table.concat(alloc_order,","))

	--同步现金桌的牌桌信息
	meta.syn_game_info()
end

function CMD.change_conf(c)
	conf = c

	alloc_order = {}
	seat_num = c.seatnum 
	if c.seatnum == 9 then
		alloc_order = ORDER9 
	elseif c.seatnum == 6 then
		alloc_order = ORDER6 
	else
		for i = 1, c.seatnum-1 do
			table.insert(alloc_order,i)
		end
		table.insert(alloc_order,0)
	end

	log.d(TAG,"change conf tablemanger[%s]",c.name)
	log.d(TAG,"seatnum[%d] lobby order: [%s]",seat_num,table.concat(alloc_order,","))
end

--客户端匹配桌子
function CMD.search(mid, old_tid)

	local ret = 200 
	local gtable 

	for _, num in ipairs(alloc_order) do 
		local list = player_table_list(num)
		if list and #list > 0 then 
			local found = false
			for index , gt in ipairs(list) do 
				if gt.tid ~= old_tid then 
					found = true
					gtable = table.remove(list,index)
					gtable.player =  gtable.player + 1 
					update_table_player(gtable)
					break
				end
			end

			if found then break end
		end
	end

	--现有的桌子都用完了，创建一个新的桌子
	if not gtable then 
		gtable = meta.create_gtable()
	end

	if gtable then 
		log.d(TAG,"player[%d] change old[%d]  to new tid[%d] player[%d] ",mid, old_tid, gtable.tid, gtable.player)
		return proto.create_resp("lobby.search",{ret=ret, lv=conf.lv, tid=gtable.tid})
	else
		log.e(TAG,"user[%d] search table failed",mid)
	end
end

--获取指定人数的桌子
function CMD.query_num_tables(num)
	local list = player_table_list(num)
	if list and next(list) then
		local t = {} 
		for _, tb in pairs(list) do 
			table.insert(t, tb.tid)
		end
		return t
	end

	return nil

end


--桌子上报人数 call by texas 
function CMD.report_table_player(tid, watcher, player)
	local gtable = gtables[tid]
	if  gtable then
		if gtable.player ~= player then 
			remove_player_list(gtable)

			gtable.player = player 

			update_table_player(gtable)
		else
			gtable.watcher = watcher 
		end

		gtable.watcher = watcher 
		log.d(TAG,"lv[%d] gtable[%d] now watcher[%d] player[%d]",conf.lv, tid, watcher, player)
	else
		log.e("report but not found tid[%d]",tid)
	end
end

function CMD.report_game_group(group, proxy)
	game_proxy[group].handler = proxy
	meta.syn_game_play_info(group, proxy)
end



skynet.start(function()

	skynet.dispatch("lua",  function(session,source,cmd,...)
		log.d(TAG,"recv cmd[%s]",cmd)
		local f = CMD[cmd]
		if f then
			if session ~= 0 then
				skynet.ret(skynet.pack(f(...)))
			else
				f( ... )
			end
		else
			log.e(TAG,"not found cmd[%s]",cmd)
		end
	end)


	skynet.fork(function()
		while true do
			skynet.sleep(6000)  --1min
			report_manager_info()
		end
    end)

    --同步在玩人数
    skynet.fork(function()
		while true do
			skynet.sleep(15000)  --2.5min
			syn_active_game_players()
		end
    end)

end)